﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTFF.WPF.Model.Artwork;
using System.Windows.Media.Imaging;
using iTFF.WPF.CP;
using System.Windows.Media;
using System.Windows.Input;
using iTFF.WPF.Resources.Languages;
using System.ComponentModel;
using System.Windows;

namespace iTFF.WPF.ViewModel
{
    class ArtworkViewModel : WorkspaceViewModel
    {
        #region Fields

        Artwork _artwork;
        RelayCommand _applyCommand;
        RelayCommand _cancelCommand;
        BackgroundWorker _applyBW;
        bool _isApplyingArtwork;
        int _progressBarValue;
        string _tempFilePath;
        bool _isApplyingAnotherArtwork;
        ArtworksViewModel _artworksViewModel;

        #endregion

        #region Constructor

        public ArtworkViewModel(Artwork artwork, ArtworksViewModel artworksViewModel)
        {
            _artwork = artwork;
            _artworksViewModel = artworksViewModel;
        }

        #endregion

        #region Base properties

        public string Artist
        {
            get { return _artwork.Artist; }
        }

        public string Album
        {
            get { return _artwork.Album; }
        }

        public string ReleaseDate
        {
            get { return _artwork.ReleaseDate; }
        }

        public string ImageURLMedium
        {
            get { return _artwork.ImageURLMedium; }
        }

        public string ImageURLBig
        {
            get { return _artwork.ImageURLBig; }
        }

        #endregion

        #region Presentation properties

        public bool IsApplyingArtwork
        {
            get { return _isApplyingArtwork; }
            set
            {
                if (_isApplyingArtwork != value)
                {
                    _isApplyingArtwork = value;
                    OnPropertyChanged("IsApplyingArtwork");
                }
            }
        }

        public int ProgressBarValue
        {
            get { return _progressBarValue; }
            set
            {
                if (_progressBarValue != value)
                {
                    _progressBarValue = value;
                    OnPropertyChanged("ProgressBarValue");
                }
            }
        }

        public bool IsApplyingAnotherArtwork
        {
            get { return _isApplyingAnotherArtwork; }
            set
            {
                if (_isApplyingAnotherArtwork != value)
                {
                    _isApplyingAnotherArtwork = value;
                    OnPropertyChanged("IsApplyingAnotherArtwork");
                }
            }
        }

        #endregion

        #region Command

        /// <summary>
        /// Applies the selected artwork to the Selected tracks (plus albums if specified)
        /// </summary>
        public ICommand ApplyCommand
        {
            get
            {
                if (_applyCommand == null)
                    _applyCommand = new RelayCommand(param => OnApplyCommand(param));
                return _applyCommand;
            }
        }

        /// <summary>
        /// Cancels the apply action
        /// </summary>
        public ICommand CancelCommand
        {
            get
            {
                if (_cancelCommand == null)
                    _cancelCommand = new RelayCommand(param => OnCancelCommand(param), param => CanExecuteCancelCommand(param));
                return _cancelCommand;
            }
        }


        /// <summary>
        /// Cancels the apply action
        /// </summary>
        private void OnCancelCommand(object param)
        {
            if (_applyBW != null && _applyBW.IsBusy)
                _applyBW.CancelAsync();
        }


        /// <summary>
        /// Gets if can cancel
        /// </summary>
        private bool CanExecuteCancelCommand(object param)
        {
            return _applyBW != null && !_applyBW.CancellationPending;
        }

        #endregion

        #region Apply

        /// <summary>
        /// Applies the selected artwork to the Selected tracks (plus albums if specified)
        /// </summary>
        private void OnApplyCommand(object param)
        {
            if (IsApplyingAnotherArtwork)
                return;

            IsApplyingArtwork = true;

            // get the actual selection
            var sel = ControlPanel.Instance.iTunesControlPanel.SelectedTracks;

            if (sel == null || sel.Length == 0)
            {
                ControlPanel.Instance.ShowBalloon("", iTFF.WinFormsWrappers.BalloonTipIcon.Warning, Strings.NoTrackSelected);
                IsApplyingArtwork = false;
                return;
            }

            // dispose the old BackgroundWorker
            if (_applyBW != null)
            {
                if (_applyBW.IsBusy)
                    _applyBW.CancelAsync();

                _applyBW.DoWork -= new DoWorkEventHandler(OnApplyBWDoWork);
                _applyBW.ProgressChanged -= new ProgressChangedEventHandler(OnApplyBWProgressChanged);
                _applyBW.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(OnApplyBWRunWorkerCompleted);
            }

            // start the background worker
            _applyBW = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
            _applyBW.DoWork += new DoWorkEventHandler(OnApplyBWDoWork);
            _applyBW.ProgressChanged += new ProgressChangedEventHandler(OnApplyBWProgressChanged);
            _applyBW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnApplyBWRunWorkerCompleted);

            _applyBW.RunWorkerAsync(sel);

        }

        void OnApplyBWDoWork(object sender, DoWorkEventArgs e)
        {
            var sel = (iTunesLib.IITTrack[])e.Argument;

            _applyBW.ReportProgress(10);

            // download the file
            try
            {
                if (!Settings.Default.ArtworkStoreMinimizedImage && !string.IsNullOrEmpty(this.ImageURLBig))
                    _tempFilePath = ControlPanel.Instance.ArtworksControlPanel.DownloadImageToTempFile(this.ImageURLBig);
                else
                    _tempFilePath = ControlPanel.Instance.ArtworksControlPanel.DownloadImageToTempFile(this.ImageURLMedium);
            }
            catch (ApplicationException ae)
            {
                ControlPanel.Instance.ShowError(ae);
                return;
            }

            // break if cancellation pending
            if (_applyBW.CancellationPending)
            {
                e.Cancel = true;
                return;
            }

            _applyBW.ReportProgress(30);

            // selected distinct albums 
            var albums = sel.Distinct(new TrackAlbumComparer()).ToArray();

            // extend the selection to albums
            if (Settings.Default.ArtworkApplyAlbums)
            {

                // extends selected tracks
                foreach (var track in albums)
                {
                    var moreTracks = ControlPanel.Instance.iTunesControlPanel.GetAllTracksInSameAlbum(track);
                    if (moreTracks == null)
                    {
                        // means iTunes is busy
                        e.Cancel = true;
                        throw new ApplicationException(Strings.iTunesBecameBusy);
                    }
                    sel = sel.Union(moreTracks).ToArray();

                    // break if cancellation pending
                    if (_applyBW.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }
                }

            }

            _applyBW.ReportProgress(50);

            // ask confirmation if multiples albums
            if (albums.Length > 1)
            {
                switch (MessageBox.Show(Strings.ArtworkViewModelMultipleAlbumConfirmation, Strings.AreYouSure,
                    MessageBoxButton.YesNoCancel, MessageBoxImage.Warning))
                {
                    case MessageBoxResult.Yes:
                        // just continue
                        break;
                    default:
                        e.Cancel = true;
                        return;
                }
            }

            // apply to selection
            // can raise ApplicationException, message will be shown in RunWorkerCompleted
            ControlPanel.Instance.iTunesControlPanel.SetArtwork(_applyBW, sel, _tempFilePath);

            _applyBW.ReportProgress(100);
        }

        void OnApplyBWProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var methodName = e.UserState as string;
            if (e.UserState != null && methodName == "SetArtwork")
            {
                // apply progress after 50
                ProgressBarValue = e.ProgressPercentage / 2 + 50;
            }
            else
                ProgressBarValue = e.ProgressPercentage;
        }

        void OnApplyBWRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (e.Error is ApplicationException)
                    ControlPanel.Instance.ShowError(e.Error);
                else
                    MessageBox.Show(string.Format(Strings.ArtworksViewModelApplyError, Environment.NewLine, e.Error.Message));
            }

            // silently deletes the temp file if created, even if the backgroundworker is cancelled
            try
            {
                if (!string.IsNullOrEmpty(_tempFilePath))
                    System.IO.File.Delete(_tempFilePath);
            }
            catch (Exception)
            {
            }

            IsApplyingArtwork = false;
        }

        #endregion

        /// <summary>
        /// Compares tracks album and artist
        /// </summary>
        class TrackAlbumComparer : IEqualityComparer<iTunesLib.IITTrack>
        {
            #region IEqualityComparer<IITTrack> Members

            public bool Equals(iTunesLib.IITTrack x, iTunesLib.IITTrack y)
            {
                return x.Artist == y.Artist && x.Album == y.Album;
            }

            public int GetHashCode(iTunesLib.IITTrack obj)
            {
                return obj.trackID;
            }

            #endregion
        }
    }

}

